﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;

namespace JH
{
    /// <summary>
    /// 获取全部继承自某个类型的类类型
    /// </summary>
    public static class GetAllDerivedTypes
    {
        /// <summary>
        ///  缓存派生类型
        /// </summary>
        private static readonly Dictionary<Type, List<Type>> DerivedTypesCache = new Dictionary<Type, List<Type>>();

        /// <summary>
        /// 获取全部继承自某个类型的类型
        /// </summary>
        public static List<Type> GetAllDerivedTypesEm(this Type type, bool throwOnAssemblyLoadError = true,
            Predicate<Type> filter = null)
        {
            if (type == null) throw new ArgumentNullException(nameof(type), "传入了空的Type");

            if (DerivedTypesCache.TryGetValue(type, out var cachedTypes))
                return ApplyFilter(cachedTypes, filter);

            var derivedTypes = new List<Type>();
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    derivedTypes.AddRange(assembly.GetTypes().Where(t => IsDerivedFrom(t, type)));
                }
                catch (ReflectionTypeLoadException )
                {
                    if (!throwOnAssemblyLoadError) continue;
                    
                    // 处理无法加载的类型
                    Debug.LogError("无法加载程序集 {assembly.FullName} 中的某些类型: {ex.Message}");
                    throw;
                }
            }

            DerivedTypesCache[type] = derivedTypes;
            return ApplyFilter(derivedTypes, filter);
        }

        /// <summary>
        ///  判断是否为派生类
        /// </summary>
        /// <param name="derivedType">需要判断的派生类型</param>
        /// <param name="baseType">基类型</param>
        /// <returns>true 表示是派生类，否则为 false</returns>
        private static bool IsDerivedFrom(Type derivedType, Type baseType)
        {
            if (baseType.IsGenericTypeDefinition)
            {
                return IsSubclassOfRawGeneric(derivedType, baseType);
            }

            return (baseType.IsClass && derivedType.IsSubclassOf(baseType)) ||
                   (baseType.IsInterface && baseType.IsAssignableFrom(derivedType) && derivedType != baseType);
        }


        /// <summary>
        /// 检查一个类型是否是原始泛型类型的子类
        /// </summary>
        /// <param name="derivedType">需要检查的类型</param>
        ///  <param name="genericBaseType">泛型基类型</param>
        ///   <returns>如果是原始泛型类型的子类，则为 true；否则为 false</returns>
        private static bool IsSubclassOfRawGeneric(Type derivedType, Type genericBaseType)
        {
            // 循环检查继承链,直到达到 object 类型或者 null
            while (derivedType != null && derivedType != typeof(object))
            {
                // 如果当前类型是泛型,获取其泛型类型定义；否则使用当前类型
                var currentType = derivedType.IsGenericType ? derivedType.GetGenericTypeDefinition() : derivedType;

                // 如果当前类型与目标泛型基类型相同,返回 true
                if (genericBaseType == currentType)
                {
                    return true;
                }

                // 移动到父类,继续检查
                derivedType = derivedType.BaseType;
            }

            // 如果检查完整个继承链都没有找到匹配,返回 false
            return false;
        }

        /// <summary>
        ///  应用过滤器
        /// </summary>
        private static List<Type> ApplyFilter(List<Type> types, Predicate<Type> filter)
        {
            return filter != null ? types.FindAll(filter) : new List<Type>(types);
        }
    }
}